﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;

namespace CsCQ_Core
{
    public static class AssemblyExtension
    {
        private readonly static Dictionary<string, Assembly> _assemblies = new Dictionary<string, Assembly>();

        static AssemblyExtension()
        {

        }

        public static IEnumerable<Type> GetTypes<T>()
        {
            var t = typeof(T);

            return _assemblies.Values.SelectMany(GetTypes<T>);
        }

        public static IEnumerable<Type> GetTypes<T>(Assembly p_assembly)
        {
            var types = p_assembly.GetTypes();

            var t = typeof(T);

            return types.Where(type => type.IsClass).Where(type => t.IsAssignableFrom(type) && t != type);
        }

        public static IEnumerable<T> GetInstances<T>()
        {
            List<T> list = new List<T>();

            var types = GetTypes<T>();

            foreach (var type in types)
            {
                try
                {
                    if (type.IsAbstract)
                    {
                        continue;
                    }

                    var instance = (T)Activator.CreateInstance(type);
                    list.Add(instance);
                }
                catch (Exception)
                {
                    //
                }
            }

            return list;
        }

        public static IEnumerable<T> GetInstances<T>(Assembly p_assembly)
        {
            List<T> list = new List<T>();
            var types = GetTypes<T>(p_assembly);

            foreach (var type in types)
            {
                try
                {
                    if (type.IsAbstract)
                    {
                        continue;
                    }

                    var instance = (T)Activator.CreateInstance(type);
                    list.Add(instance);
                }
                catch (Exception)
                {
                    //
                }
            }

            return list;
        }

        public static void LoadAssemblys(string path = "./cs/")
        {
            var files = Directory.GetFiles(path, "*.dll");
            foreach (var file in files)
            {
                if (file.EndsWith("CsCQ.Core.dll", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }
                LoadAssembly(file);
            }
        }

        public static Assembly LoadAssembly(string p_file)
        {
            Assembly assmebly = null;

            try
            {
                if (!File.Exists(p_file))
                {
                    RemoveAssembly(p_file);
                    return null;
                }

                var buffer = File.ReadAllBytes(p_file);
                assmebly = Assembly.Load(buffer);
                if (assmebly == null)
                {
                    return null;
                }

                var key = Path.GetFileName(p_file);
                _assemblies[key] = assmebly;
            }
            catch (Exception)
            {
                //
            }

            return assmebly;
        }

        public static void RemoveAssembly(string p_file)
        {
            var key = Path.GetFileName(p_file);
            if (string.IsNullOrEmpty(key))
            {
                return;
            }

            if (!_assemblies.ContainsKey(key))
            {
                return;
            }

            _assemblies.Remove(key);
        }
    }
}